import functools
import threading


def singleton(cls):
    """ Use class as singleton. """

    cls.__new_original__ = cls.__new__

    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        it = cls.__dict__.get('__it__')
        if it is not None:
            return it

        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it

    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__

    return cls


def synchronized(func):
    """ Make a normal function synchronized. """

    func.__lock__ = threading.Lock()

    def synced_func(*args, **kwargs):
        with func.__lock__:
            return func(*args, **kwargs)

    return synced_func


def switch(value, fall_through=False):
    """Simulate Switch/Case structure
        usage:
            for case in Switch(value):
                if case(arg):
                    pass
    """
    fall = False

    def match(*args):
        nonlocal value, fall, fall_through
        if (fall_through and fall) or not args:
            return True
        elif (value in args) or (callable(args[0]) and args[0](value)):
            fall = True
            return True
        else:
            return False

    yield match
